package com.core.image.core.impl;
import com.core.image.core.*;
import com.core.image.utils.CloseUtils;
import java.io.IOException;
import java.nio.channels.SocketChannel;
import java.util.concurrent.atomic.AtomicBoolean;

public class SocketChannelAdapter implements Sender, Receiver, Cloneable {
    private final AtomicBoolean isClosed = new AtomicBoolean(false);
    private final SocketChannel channel;
    private final IoProvider ioProvider;
    private final OnChannelStatusChangedListener listener;
    private IoArgs.IoArgsEventProcessor receiveIoEventListener;
    private IoArgs.IoArgsEventProcessor sendIoEventListener;
    // 最后活跃时间点
    private volatile long lastReadTime = System.currentTimeMillis();
    private volatile long lastWriteTime = System.currentTimeMillis();
    public SocketChannelAdapter(SocketChannel channel, IoProvider ioProvider,
                                OnChannelStatusChangedListener listener) throws IOException {
        this.channel = channel;
        this.ioProvider = ioProvider;
        this.listener = listener;
        channel.configureBlocking(false);
    }

    @Override
    public void setReceiveListener(IoArgs.IoArgsEventProcessor listener) {
        this.receiveIoEventListener = listener;
    }

    @Override
    public void setSendListener(IoArgs.IoArgsEventProcessor listener) {
            this.sendIoEventListener = listener;
    }

    @Override
    public boolean postReceiveAsync() throws IOException {
        if (isClosed.get()) {
            throw new IOException("Current channel is closed!");
        }
        inputCallback.checkAttachNull();
        return ioProvider.registerInput(channel,inputCallback);
    }

    @Override
    public long LastReadTime() {
        return lastReadTime;
    }


    @Override
    public boolean postSendAsync() throws IOException {
        if (isClosed.get()) {
            throw new IOException("Current channel is closed!");
        }
        outputCallback.checkAttachNull();
        return ioProvider.registerOutput(channel, outputCallback);
    }

    @Override
    public long getLastWriteTime() {
        return lastWriteTime;
    }

    @Override
    public void close() throws IOException {
        if (isClosed.compareAndSet(false, true)) {
            // 解除注册回调
            ioProvider.unRegisterInput(channel);
            ioProvider.unRegisterOutput(channel);
            // 关闭
            CloseUtils.close(channel);
            // 回调当前Channel已关闭
            listener.onChannelClosed(channel);
        }
    }

    private final IoProvider.HandleProviderCallback inputCallback = new IoProvider.HandleProviderCallback() {
            @Override
            protected void onProviderTo(IoArgs args) {
                if (isClosed.get()) {
                    return;
                }
                //刷新读取时间
                lastReadTime = System.currentTimeMillis();
                IoArgs.IoArgsEventProcessor listener = receiveIoEventListener;
                if (args == null) {
                    args = listener.provideIoArgs();
                }
                try {
                    if (args == null) {
                        listener.onConsumeFailed(null, new IOException("数据读取失败"));
                    }
                    int count = args.readFrom(channel);
                    // 具体的读取操作
                    if (args.remained() && args.isNeedConsumeRemaining()){
                        // 读取完成回调
                        attach = args;
                        ioProvider.registerInput(channel,this);
                    } else{
                        attach = null;
                        listener.onConsumeComplete(args);
                    }
                } catch (Exception ignored) {
                    CloseUtils.close(SocketChannelAdapter.this);
                }
            }
        };

    private final IoProvider.HandleProviderCallback outputCallback = new IoProvider.HandleProviderCallback() {
        @Override
        protected void onProviderTo(IoArgs args) {
            if (isClosed.get()) {
                return;
            }
            // 刷新输出时间
            lastWriteTime = System.currentTimeMillis();
            IoArgs.IoArgsEventProcessor listener = sendIoEventListener;
             if (args == null){
                 args = listener.provideIoArgs();
             }
            try {
                if (args == null){
                    listener.onConsumeFailed(null,new IOException("数据读取失败"));
                }
                int count = args.writeTo(channel);
                if (args.remained() && args.isNeedConsumeRemaining() ){
                    attach =args;
                   ioProvider.registerOutput(channel,this);
                }else {
                    attach = null;
                    listener.onConsumeComplete(args);
                }
            }catch (Exception e){
                CloseUtils.close(SocketChannelAdapter.this);
            }
        }
    };



    public interface OnChannelStatusChangedListener {
        void onChannelClosed(SocketChannel channel);
    }
}
